﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace MR_HKSUtility
{
    /**
     * Multimedia Retrieval
     * Heat Kernel Signature project
     * Frank Borgonjen, Joeri van der Lei & Kevin van der Lei
     * 28-10-2011
     * 
     * The Storage class is a utility class containing methods to store heat kernel data using serialization, 
     * which improves efficiency in storing and loading.
     */
    public class Storage
    {
        #region Variables

        // directory where data will be stored
        private String outputDir;
        private Dictionary<String, double[]> dictionary = null;

        #endregion

        #region Functions

        /**
         * Constructs an instance of Storage using the given output directory.
         * @param outputDir the name of the directory where data should be stored.
         */
        public Storage(string outputDir)
        {
            this.outputDir = outputDir;
        }

        /**
         * Stores the given HKS values using the given file name.
         * @param offFileName the name of the .off file the given HKS values were generated from.
         * @param values an array containing the HKS values to be stored.
         */
        public void saveHKSValues(String offFileName, double[] values)
        {
            loadHKSDictionary();
            dictionary.Remove(offFileName);
            dictionary.Add(offFileName, values);

            // serialize dictionary
            String dictionaryFile = outputDir + "\\HKS_values.hks";
            serializeObject(dictionary, dictionaryFile);
            Console.WriteLine("Dictionary Saved");
        }

        /**
         * Returns the HKS values associated with the given file name.
         * @param offFileName the file name for which the associated HKS values should be looked up.
         */
        public double[] getHKSValues(String offFileName)
        {
            loadHKSDictionary();
            return dictionary[offFileName];
        }

        /**
         * Returns the number of .off files for which HKS values have been stored.
         */
        public int getNumberOfFiles()
        {
            loadHKSDictionary();
            return dictionary.Keys.Count;
        }

        /**
         * Returns an array containing the file names of all .off files for which the HKS values have
         * been stored.
         */
        public String[] getKeys()
        {
            loadHKSDictionary();
            return dictionary.Keys.ToArray();
        }

        /**
         * Loads the HKS dictionary from the stored output directory.
         */
        private void loadHKSDictionary()
        {
            if (dictionary == null)
            {
                String dictionaryFile = outputDir + "\\HKS_values.hks";
                if (File.Exists(dictionaryFile))
                {
                    dictionary = (Dictionary<String, double[]>) deSerializeObject(dictionaryFile);
                }
                else
                {
                    dictionary = new Dictionary<String, double[]>();
                }
            }
        }

        /**
         * Serializes the given object and saves it with the given file name.
         */
        private void serializeObject(Object o, String outputFileName)
        {
            Stream stream = File.Open(outputFileName, FileMode.Create);
            BinaryFormatter bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, o);
            stream.Close();
        }

        /**
         * Deserializes the object with the given file name and returns it.
         */
        private Object deSerializeObject(String fileName)
        {
            Stream stream = File.Open(fileName, FileMode.Open);
            BinaryFormatter bFormatter = new BinaryFormatter();
            Object result = bFormatter.Deserialize(stream);
            stream.Close();

            return result;
        }

        #endregion
    }
}
